﻿#if SRP_URP
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;

namespace GameToolkit
{
    [System.Serializable, VolumeComponentMenu("Custom/Blur Screen Effect")]
    public class BlurScreenEffect : ImageEffectPassData, ImageEffectPassBlitter, ImageEffectPassSetup, ICacheableVolumeComponent
    {
        public VolumeParameter<EMipmapQuality> m_Resolution = new VolumeParameter<EMipmapQuality> { value = EMipmapQuality.QuaterRes };

        public ClampedFloatParameter m_SampleRadius = new ClampedFloatParameter(0.2f, 0, 3f);
        public ClampedIntParameter m_SampleCount = new ClampedIntParameter(3, 1, 8);

        //List<CustomPostProcessPassID> mPasses = new List<CustomPostProcessPassID>
        //    { new CustomPostProcessPassID(0, RenderPassEvent.AfterRenderingPostProcessing) };

        Material mMaterial;
        bool mWasInitialized;
        int sh_uvOffset;
        RTHandle sh_tmpRt1;
        RTHandle sh_tmpRt2;
        Vector2 mUvOffset;

        //public IList<CustomPostProcessPassID> GetPasses()
        //{
        //    return mPasses;
        //}

        void Initialize()
        {
            if (!mWasInitialized)
            {
                mWasInitialized = true;
                sh_uvOffset = Shader.PropertyToID("_UvOffset");
                //sh_tmpRt1 = Shader.PropertyToID("_temp1");
                //sh_tmpRt2 = Shader.PropertyToID("_temp2");
            }
        }

        void Release(ref RTHandle rt)
        {
            if (rt != null)
            {
                rt.Release();
                rt = null;
            }
        }

        public override void OnActivite(CustomVolumeRenderer volr)
        {
            Initialize();
            if (mMaterial == null)
                mMaterial = volr.GetAsset<Material>("PostProcess_Blur");
        }

        public override void OnDeactivite(CustomVolumeRenderer volr)
        {
            Release(ref sh_tmpRt1);
            Release(ref sh_tmpRt2);
        }

        public override void OnSetupBlitterPassData(ImageEffectPass pass)
        {
            if(mMaterial != null)
            {
                pass.EnqueueBliterPass(new ImageEffectPass.PassData(ImageEffectPass.InjectionPoint.BeforeRenderingPostProcessing, mMaterial, 0), this, this);
            }
        }

        void ImageEffectPassSetup.OnCameraSetup(CommandBuffer cmd, ref RenderingData renderingData)
        {
            var texDesc = renderingData.cameraData.cameraTargetDescriptor;
            var width = texDesc.width >> (int)m_Resolution.value;
            var height = texDesc.height >> (int)m_Resolution.value;
            //var mask = (1 << (int)component.m_Resolution.value) - 1;
            //var fix_x = component.m_Resolution.value == 0 ? 0 : 1;
            //var fix_y = (height & mask) == 0 ? 0 : 1;
            texDesc.width = width;
            texDesc.height = height;
            texDesc.msaaSamples = 1;
            texDesc.useMipMap = false;
            texDesc.depthBufferBits = (int)DepthBits.None;
            mUvOffset.x = 1f / (float)texDesc.width;
            mUvOffset.y = 1f / (float)texDesc.height;
            RenderingUtils.ReAllocateIfNeeded(ref sh_tmpRt1, texDesc, wrapMode: TextureWrapMode.Clamp, filterMode: FilterMode.Bilinear, name: "tmpRt1");
            RenderingUtils.ReAllocateIfNeeded(ref sh_tmpRt2, texDesc, wrapMode: TextureWrapMode.Clamp, filterMode: FilterMode.Bilinear, name: "tmpRt2");
        }

        void ImageEffectPassBlitter.Blit(CommandBuffer cmd, RTHandle source, RTHandle dest, ImageEffectPass.PassData passData)
        {
            var step = m_SampleRadius.value * mUvOffset;
            var count = m_SampleCount.value;
            Vector4 scaleBias = new Vector4(1, 1, 0, 0);
            cmd.SetGlobalVector(sh_uvOffset, step);
            //pass.Blit(cmd, pass.UsingRenderer.cameraColorTarget, component.sh_tmpRt1, component.mMaterial, 0);
            CoreUtils.SetRenderTarget(cmd, sh_tmpRt1);
            Blitter.BlitTexture(cmd, source, scaleBias, passData.material, passData.passIndex);
            var rt = sh_tmpRt1;
            var scale = 1f / (1 << (int)m_Resolution.value);
            scaleBias = new Vector4(scale, scale, 0, 0);
            for (int i = 1; i < count; i++)
            {
                rt = rt == sh_tmpRt1 ? sh_tmpRt2 : sh_tmpRt1;
                var src = rt == sh_tmpRt1 ? sh_tmpRt2 : sh_tmpRt1;
                step += step * 0.7f;
                cmd.SetGlobalVector(sh_uvOffset, step);
                CoreUtils.SetRenderTarget(cmd, rt);
                Blitter.BlitTexture(cmd, src, scaleBias, passData.material, passData.passIndex);
            }
            step += step * 0.7f;
            cmd.SetGlobalVector(sh_uvOffset, step);
            CoreUtils.SetRenderTarget(cmd, dest);
            Blitter.BlitTexture(cmd, rt, scaleBias, passData.material, passData.passIndex);
        }

        //public override void OnSetupVolumePasses(CustomVolumeRenderer volr)
        //{
        //    var pass = volr.Enqueue<Effpass>(this, renderpassevent.afterrenderingpostprocessing, 1);
        //    if (pass != null)
        //        pass.component = this;
        //}

        void ICacheableVolumeComponent.ReleaseCacheableAssets()
        {
            mMaterial = null;
        }

    }
}
#endif